# 导入所需的模块
from flask import Flask, render_template, request, redirect, url_for, jsonify, flash  # 导入Flask框架相关功能
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user  # 导入Flask-Login用于用户认证
import sqlite3  # 导入SQLite数据库模块
from contextlib import closing  # 导入上下文管理器,用于自动关闭数据库连接
from datetime import datetime  # 导入日期时间模块,用于记录时间戳
from werkzeug.security import generate_password_hash, check_password_hash  # 导入密码哈希相关功能,用于安全存储密码

# 创建Flask应用实例
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key_here'  # 设置应用的密钥,用于会话安全

# 初始化Flask-Login
login_manager = LoginManager()  # 创建LoginManager实例
login_manager.init_app(app)  # 将login_manager与app关联
login_manager.login_view = 'login'  # 设置登录视图的名称,未登录用户会被重定向到这个视图

# 定义用户类,继承自UserMixin以获得Flask-Login所需的属性和方法
class User(UserMixin):
    def __init__(self, id, username, password, is_admin=False):
        self.id = id  # 用户ID
        self.username = username  # 用户名
        self.password = password  # 密码(已哈希)
        self.is_admin = is_admin  # 是否为管理员

# 用户加载函数,供Flask-Login使用
@login_manager.user_loader
def load_user(user_id):
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        with closing(db.cursor()) as cursor:  # 创建游标
            cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))  # 查询指定ID的用户
            user = cursor.fetchone()  # 获取查询结果
            if user:  # 如果用户存在
                return User(user[0], user[1], user[2], user[3])  # 返回User对象
    return None  # 如果用户不存在,返回None

# 初始化数据库
def init_db():
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        with closing(db.cursor()) as cursor:  # 创建游标
            # 创建用户表
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS users (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    username TEXT UNIQUE NOT NULL,
                    password TEXT NOT NULL,
                    is_admin BOOLEAN NOT NULL DEFAULT 0
                )
            ''')
            # 创建管理员用户（如果不存在）
            cursor.execute("SELECT * FROM users WHERE username = 'admin'")  # 查询是否存在admin用户
            if not cursor.fetchone():  # 如果admin用户不存在
                admin_password = generate_password_hash('admin')  # 生成admin密码的哈希值
                cursor.execute("INSERT INTO users (username, password, is_admin) VALUES (?, ?, ?)",
                               ('admin', admin_password, True))  # 插入admin用户
            
            # 创建待办事项表
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS todos (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    user_id INTEGER NOT NULL,
                    text TEXT NOT NULL,
                    completed BOOLEAN NOT NULL,
                    created_at TIMESTAMP NOT NULL,
                    updated_at TIMESTAMP NOT NULL,
                    deleted BOOLEAN NOT NULL DEFAULT 0,
                    FOREIGN KEY (user_id) REFERENCES users (id)
                )
            ''')
            
            # 检查user_id列是否存在,如果不存在则添加
            cursor.execute("PRAGMA table_info(todos)")  # 获取todos表的结构信息
            columns = [column[1] for column in cursor.fetchall()]  # 提取列名
            if 'user_id' not in columns:  # 如果user_id列不存在
                cursor.execute('ALTER TABLE todos ADD COLUMN user_id INTEGER NOT NULL DEFAULT 1')  # 添加user_id列
        db.commit()  # 提交事务

# 获取所有未删除的待办事项
def get_todos():
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        db.row_factory = sqlite3.Row  # 设置行工厂,使结果可以通过列名访问
        with closing(db.cursor()) as cursor:  # 创建游标
            cursor.execute('SELECT * FROM todos WHERE deleted = 0 ORDER BY created_at DESC')  # 查询未删除的待办事项,按创建时间降序排序
            return [dict(row) for row in cursor.fetchall()]  # 将结果转换为字典列表并返回

# 主页路由
@app.route('/')
def index():
    todos = get_todos()  # 获取所有未删除的待办事项
    return render_template('index.html', todos=todos)  # 渲染index.html模板,传入todos数据

# 添加待办事项路由
@app.route('/add', methods=['POST'])
def add_todo():
    todo = request.form.get('todo')  # 获取表单中的todo内容
    if todo:  # 如果todo不为空
        now = datetime.now().isoformat()  # 获取当前时间的ISO格式字符串
        with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
            with closing(db.cursor()) as cursor:  # 创建游标
                cursor.execute('INSERT INTO todos (text, completed, created_at, updated_at, user_id) VALUES (?, ?, ?, ?, ?)',
                               (todo, False, now, now, 1))  # 插入新的待办事项,使用默认用户ID 1
            db.commit()  # 提交事务
    return redirect(url_for('index'))  # 重定向到主页

# 删除待办事项路由
@app.route('/delete/<int:todo_id>')
def delete_todo(todo_id):
    now = datetime.now().isoformat()  # 获取当前时间的ISO格式字符串
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        with closing(db.cursor()) as cursor:  # 创建游标
            cursor.execute('UPDATE todos SET deleted = 1, updated_at = ? WHERE id = ?', (now, todo_id))  # 将待办事项标记为删除
        db.commit()  # 提交事务
    return redirect(url_for('index'))  # 重定向到主页

# 切换待办事项完成状态路由
@app.route('/toggle/<int:todo_id>', methods=['POST'])
def toggle_todo(todo_id):
    now = datetime.now().isoformat()  # 获取当前时间的ISO格式字符串
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        with closing(db.cursor()) as cursor:  # 创建游标
            cursor.execute('UPDATE todos SET completed = NOT completed, updated_at = ? WHERE id = ?', (now, todo_id))  # 切换完成状态
        db.commit()  # 提交事务
    return jsonify({"success": True})  # 返回JSON响应,表示操作成功

# 调试路由（需要管理员权限）
@app.route('/debug')
@login_required  # 要求用户登录
def debug():
    if not current_user.is_admin:  # 如果当前用户不是管理员
        flash('You do not have permission to access this page')  # 显示错误消息
        return redirect(url_for('index'))  # 重定向到主页
    with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
        db.row_factory = sqlite3.Row  # 设置行工厂,使结果可以通过列名访问
        with closing(db.cursor()) as cursor:  # 创建游标
            cursor.execute('SELECT * FROM todos ORDER BY created_at DESC')  # 查询所有待办事项,按创建时间降序排序
            todos = [dict(row) for row in cursor.fetchall()]  # 将结果转换为字典列表
    return jsonify(todos)  # 返回JSON格式的所有待办事项

# 登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':  # 如果是POST请求
        username = request.form['username']  # 获取表单中的用户名
        password = request.form['password']  # 获取表单中的密码
        with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
            with closing(db.cursor()) as cursor:  # 创建游标
                cursor.execute("SELECT * FROM users WHERE username = ?", (username,))  # 查询指定用户名的用户
                user = cursor.fetchone()  # 获取查询结果
                if user and check_password_hash(user[2], password):  # 如果用户存在且密码正确
                    login_user(User(user[0], user[1], user[2], user[3]))  # 登录用户
                    return redirect(url_for('index'))  # 重定向到主页
        flash('Invalid username or password')  # 如果登录失败,显示错误消息
    return render_template('login.html')  # 渲染登录页面

# 登出路由
@app.route('/logout')
@login_required  # 要求用户登录
def logout():
    logout_user()  # 登出用户
    return redirect(url_for('index'))  # 重定向到主页

# 注册路由
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':  # 如果是POST请求
        username = request.form['username']  # 获取表单中的用户名
        password = request.form['password']  # 获取表单中的密码
        with closing(sqlite3.connect('todos.db')) as db:  # 连接数据库
            with closing(db.cursor()) as cursor:  # 创建游标
                try:
                    cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)",
                                   (username, generate_password_hash(password)))  # 插入新用户
                    db.commit()  # 提交事务
                    flash('Registration successful. Please log in.')  # 显示注册成功消息
                    return redirect(url_for('login'))  # 重定向到登录页面
                except sqlite3.IntegrityError:  # 如果用户名已存在
                    flash('Username already exists')  # 显示错误消息
    return render_template('register.html')  # 渲染注册页面

# 主程序入口
if __name__ == '__main__':
    init_db()  # 初始化数据库
    app.run(debug=True)  # 以调试模式运行应用